﻿/*
 * @Autor: PK
 * @Date: 2021/12/06 10:20:SS
 */

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Data;
using ShkSimulation.core.dao.input.resource;
using ShkSimulation.core.exceptions;
using ShkSimulation.core.template;

namespace ShkSimulation.core.optimization.extractor {

	public class NamedMatrixDecisionVariableExtractor : NamedDecisionVariableExtractor{

		private readonly NamedCellPointGroup namedCellPointGroup;

		public NamedMatrixDecisionVariableExtractor(NamedCellPointGroup namedCellPointGroup) {
			this.namedCellPointGroup = namedCellPointGroup;
		}

		public Dictionary<string, double> ExtractNamedDecisionVariables(NetworkInputData inputData) {
			IReadOnlyDictionary<string, Resource> allInputData = inputData.AllResources;
			Dictionary<string, double> result = new Dictionary<string, double>();
			foreach ((string table, var pair) in namedCellPointGroup.location) {
				if (!allInputData.ContainsKey(table)) {
					throw new ErrorParamException("不存在表：" + table);
				}
				DataTable data = allInputData[table].GetDataTable();
				foreach ((string name, CellPoint point) in pair) {
					if (point.Row >= data.Rows.Count || point.Column >= data.Columns.Count) {
						throw new ErrorParamException("属性提取器超过了索引：" + name);
					}
					result.Add(name, Convert.ToDouble(data.Rows[point.Row][point.Column]));
				}
			}
			return result;
		}

		public double[] ExtractDecisionVariables(NetworkInputData inputData) {
			Dictionary<string, double> variables = ExtractNamedDecisionVariables(inputData);
			ImmutableSortedSet<string> orderedKeys = namedCellPointGroup.GetSortedName();
			double[] result = new double[variables.Count];
			int index = 0;
			foreach (var key in orderedKeys) {
				result[index] = variables[key];
				index++;
			}
			return result;
		}

		public NetworkInputData CloneThenInjectNamedDecisionVariables(NetworkInputData sourceData, Dictionary<string, double> decisionVariables) {
			NetworkInputData inputData = sourceData.Clone();
			IReadOnlyDictionary<string, Resource> allInputData = inputData.AllResources;
			foreach ((string table, var pair) in namedCellPointGroup.location) {
				if (!allInputData.ContainsKey(table)) {
					throw new ErrorParamException($"不存在表：{table}");
				}
				Resource resource = allInputData[table];
				DataTable data = resource.GetDataTable();
				foreach ((string name, CellPoint point) in pair) {
					if (point.Row >= data.Rows.Count || point.Column >= data.Columns.Count) {
						throw new ErrorParamException($"属性提取器超过了索引：{name}");
					}
					if (decisionVariables.ContainsKey(name)) {
						data.Rows[point.Row][point.Column] = decisionVariables[name];
					} else {
						// 没有这个值, FBI warning
						throw new ErrorParamException($"新数据不存在决策变量：{name}");
					}
				}
				inputData.UpdateResource(table, resource);
			}
			return inputData;
		}
		
		public NetworkInputData CloneThenInjectDecisionVariables(NetworkInputData inputData, double[] decisionVariables) {
			ImmutableSortedSet<string> orderedKeys = namedCellPointGroup.GetSortedName();
			if (decisionVariables == null || orderedKeys.Count != decisionVariables.Length) {
				throw new ErrorParamException($"更新的数据：{decisionVariables} 和提取器提取属性长度不一致：{orderedKeys.Count}");
			}
			Dictionary<string, double> toUpdate = new Dictionary<string, double>();
			for (var i = 0; i < orderedKeys.Count; i++) {
				toUpdate.Add(orderedKeys[i], decisionVariables[i]);
			}
			return CloneThenInjectNamedDecisionVariables(inputData, toUpdate);
		}

	}
}